/*
Copyright 2011, CSE Shareware Foundation
All rights reserved.

Redistribution and use in source and binary forms, with or without modification, 
are permitted provided that the following conditions are met:

 * Redistributions of source code must retain the above copyright notice, 
   this list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright notice, 
   this list of conditions and the following disclaimer in the documentation 
   and/or other materials provided with the distribution.
 * Neither the name of CSE Shareware Foundation nor the names of its contributors 
   may be used to endorse or promote products derived from this software without 
   specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 
OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#if defined(__GNUC__) && !defined(__MINGW32__)
  #include <sched.h>
#else
  #include <windows.h>
#endif

#include "CseApi_.h"

// variable defined in CseNum.cpp
//==============================================================================
#ifndef CLOSE_REF_CHECK
  TInt32 gTotalIntObjCount = 0;
  TInt32 gTotalWintObjCount = 0;
  TInt32 gTotalFloatObjCount = 0;
#endif

// variable defined in CharArray.cpp
//==============================================================================
#ifndef CLOSE_REF_CHECK
  TInt32 gTotalCharArrayCount = 0;
#endif

TCriticalSection *CseCharBuffLock = NULL;

struct _RSVD_CHARARRAY
{
    TUint32 iSize;
    TUint32 iLen;
    TXchar sValue[1];
} __RsvdCharArray = {0,0,{_T('\0')}};

TXchar *__EmptyString = __RsvdCharArray.sValue;
const TCharArray& CseEmptyStr = (TCharArray&) __EmptyString;

TCharArray *Cse_LastErrName = NULL;
TCharArray *Cse_LastErrDesc = NULL;

// variable defined in IntArray.cpp
//==============================================================================
#ifndef CLOSE_REF_CHECK
  TInt32 gTotalIntArrayCount = 0;
#endif

TCriticalSection *CseIntBuffLock = NULL;

struct _RSVD_INTARRAY
{
    TUint32 iSize;
    TUint32 iLen;
    TInt tValue[1];
} __RsvdIntArray = {0,0,{0}};

TInt *__EmptyTier = __RsvdIntArray.tValue;
const TIntArray& CseEmptyTier = (TIntArray&)__EmptyTier;

// variable defined in ObjArray.cpp
//==============================================================================
#ifndef CLOSE_REF_CHECK
  TInt32 gTotalObjArrayCount = 0;
#endif

STATIC CSE_BASE_TYPE __DummyValue = {0x0FFFFFFF,0,0};
CseObj dummy = &__DummyValue.context;

TCriticalSection *CseObjBuffLock = NULL;

struct _RSVD_OBJARRAY
{
    TUint32 iSize;
    TUint32 iLen;
    CseObj bValue[1];
} __RsvdObjArray = {0,0,{NULL}};

CseObj *__EmptyBuff = __RsvdObjArray.bValue;
const TObjArray& CseEmptyBuff = (TObjArray&) __EmptyBuff;

// variable defined in EntryArray.cpp
//==============================================================================
#ifndef CLOSE_REF_CHECK
  TInt32 gTotalEntryArrayCount = 0;
#endif

TCriticalSection *CseEntryBuffLock = NULL;

STATIC PEntryPoint _EmptyDict = NULL;
const TEntryArray& CseEmptyDict = (TEntryArray&) _EmptyDict;

CseObj CseNull = NULL;

// variable defined in BaseTypes.cpp
//==============================================================================
TBool gAssertIsReady       = false;
TBool gCheckRefCount       = true;
TBool gHitBeforeExit       = false;
TUint32 gCseObjectRefs[17] = {0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0};

CseObj gCseDisableLnDbg    = NULL;
CseObj gExistIDs           = NULL;

FreeObjFunc gFreeObjProc[17] = { NULL,NULL,NULL,NULL,NULL,
              NULL,NULL,NULL,NULL,NULL, NULL,NULL,NULL,NULL,NULL, NULL,NULL };

CseObj gCseRegistTable    = NULL;
CseObj gCsePreserves      = NULL;

CseObj gCseTypeStrFunc    = NULL;
CseObj gCseInstFreeFunc   = NULL;
CseObj gCseInstCmpFunc    = NULL;
CseObj gCseInstEqualFunc  = NULL;
CseObj gCseInstStrFunc    = NULL;
CseObj gCseInstBeStrFunc  = NULL;
CseObj gCseInstAsKeyFunc  = NULL;
CseObj gCseInstMapVarFunc = NULL;
CseObj gCseLogErrorStack  = NULL;

CseObj CseBltinModule     = NULL;
CseObj CseMainModule      = NULL;

CseObj CseEmptySpace      = NULL;
CseObj CseThreadStacks    = NULL;
CseObj CseTraceStack      = NULL;

#ifndef CLOSE_REF_CHECK
  TInt32 gGlobalCharArrayCount = 0;
#endif

TCriticalSection *CseRecycleLock = NULL;

// variable defined in CseObj.cpp
//==============================================================================
#ifndef CLOSE_REF_CHECK
  TInt32 gTotalCseObjCount = 0;
#endif

// variable defined in modules.cpp
//==============================================================================
CseObj constSpace,constSpaceName,constNameSpace,constBase,constVarList;
CseObj constSubs,constOnExit;

CseObj gCseDllHandles = NULL;
CseObj gCseSymTable   = NULL;
CseObj gCsePaths      = NULL;
CseObj gCseArguments  = NULL;
CseObj gCseOnExit     = NULL;
CseObj gCseModules    = NULL;

TCseRegister *CseRegister    = NULL;

CseObj gCppVoidFunc          = NULL;
CseObj gScriptEvalFunc       = NULL;
CseObj gScriptCompFunc       = NULL;

CseObj gCppStrType           = NULL;

TXchar gCseHostName[32] = {_T('\0')};

STATIC TBool ModuleIsInit = false;
STATIC int ModuleInitCount = 0;

extern "C" {
  void *Cse_FuncAddr(char *fmt,...)
  {
    va_list pArg;
    va_start(pArg,fmt);
    void *ret = va_arg(pArg,void *);
    va_end(pArg);

    return ret;
  }

  const TXchar *Cse_GetHost()
  {
    if (gCseHostName[0] == _T('\0'))
        return NULL;
    else return (const TXchar *) gCseHostName;
  }

  void Cse_SetHost(const TXchar *name)
  {
    if (name == NULL)
        gCseHostName[0] = _T('\0');
    else STRNCPY(gCseHostName,name,32);

    if (name == NULL || name[0] == _T('\0'))
        CseRegister->set(_T("KERNEL/USE_HOST"),TIntObj(0));
    else CseRegister->set(_T("KERNEL/USE_HOST"),TIntObj(1));
  }
}

TCseObj Cse_EvalScript(const TXchar *script)
{
    if (script == NULL)
        return dummy;
    else if ( gScriptEvalFunc != NULL && gScriptEvalFunc->iValue != 0 &&
              gScriptCompFunc != NULL && gScriptCompFunc->iValue != 0 )
    {   // call script exiting function
        TCseObj (*_CompileScript)(const TCharArray&,int,int,const TCseObj&) = (TCseObj (*)(const TCharArray&,int,int,const TCseObj&)) gScriptCompFunc->iValue;
        TCseObj cmd = _CompileScript(script,1,0,dummy);

        TCseObj (*_EvalNode)(const TCseObj& cmd, const TCseObj& space) = (TCseObj (*)(const TCseObj&,const TCseObj&)) gScriptEvalFunc->iValue;
        return _EvalNode(cmd,CseMainModule);
    }
    else return dummy;
}

TCharArray Cse_RawPrint(const TCharArray& s)
{
    if (s.len())
    {
        PRINTF(_T("%s\n"),s.addr());
    }
    return CseEmptyStr;
}

TCharArray Cse_RawPrompt(const TCharArray& s)
{
    TCharArray sPrompt = s.len()? s: _T(">>>");
    PRINTF(_T("%s"),sPrompt.addr());
    return CseEmptyStr;
}

// Following define TCseRegister
//==============================================================================
TBool TCseRegister::exist(const TCharArray& key) const
{
    return CseRegist_exist(key);
}

TCseObj TCseRegister::get(const TCharArray& key) const
{
    CseObj v = CseRegist_get(key);
    if (NULL == v)
        return dummy;
    else return v;
}

const TCseObj& TCseRegister::set(const TCharArray& key, const TCseObj& value) const
{
    CseRegist_set(key,value);
    return value;
}

void TCseRegister::remove(const TCharArray& key) const
{
    CseRegist_delete(key);
}

TCseObj TCseRegister::hold(const TCseObj& value) const
{
    CseRegist_hold(value);
    return value;
}

// Following define TCseModules
//==============================================================================
CseObj Cse_GetModule(const TCharArray& sModule, TBool OnlyTopLevel)
{
    if (sModule.isEmpty()) return NULL;

    TCharArray sName = ExtractFileName(sModule);

    sName.upper();
    if (sName == _T("__BLTIN__"))
        return CseBltinModule;
    else if (sName == _T("__MAIN__"))
        return CseMainModule;

    // First search top modules, CseModules: [[#Name,vModule], ... ]
    TCseObj vName(sName);
    int iCount, iLen = Cse_len(gCseModules);
    for (iCount = 0; iCount < iLen; iCount++)
    {
        TCseObj v = gCseModules->bValue[iCount];
        if (dtBuff == v.type() && v.len() == 2)
        {
            if (vName == v.sub(0))
                return v->bValue[1];
        }
    }
    if (OnlyTopLevel) return NULL;

    // Next search from every package
    for (iCount = 0; iCount < iLen; iCount++)
    {
        TCseObj v = gCseModules->bValue[iCount];
        if (dtBuff == v.type() && v.len() == 2)
        {
            v = v[1];  // Get one top module
            CHECK_TRUE(v.isSpace());
            
            TCseObj bSubs = v.get(constSubs); // [sModule,#name, ...]
            if (dummy == bSubs) continue;
            ASSERT_TRUE(bSubs.type() == dtBuff);

            for (int index = 1; index < bSubs.len(); index += 2)
            {
                TCharArray sDesc = bSubs[index-1].beStr();
                if (sName == sDesc.upper())
                {
                    TCseObj value = v.get(bSubs[index]);
                    if (value.isSpace()) return value;
                }
            }
        }
    }
    return NULL;
}

STATIC void TryRunExitFunc(const TCseObj& vFunc, TBool safeExit, const TCseObj& space)
{
    if (vFunc.type() == dtInstance && vFunc.len() == 3 && gCppVoidFunc == vFunc.sub(0))
    {   // call C/C++ exiting function
        TCseObj v = vFunc.sub(1);
        if (v.type() == dtWeak)
        {
            void (*func)() = (void (*)()) (v->iValue + vFunc.sub(2)->iValue);

            if (safeExit)
            {   // if meet error, just ignore it
                try
                {
                    func();
                }
                catch(...)
                {}
            }
            else func();
        }
    }
    else if (ModuleIsInit && gScriptEvalFunc != NULL && gScriptEvalFunc->iValue != 0)
    {   // call script exiting function
        TCseObj cmd = TCseObj::format(CSE_NOTATOR,*(CseObj*)&vFunc);
        TCseObj (*_EvalNode)(const TCseObj& cmd, const TCseObj& space) = (TCseObj (*)(const TCseObj&,const TCseObj&)) gScriptEvalFunc->iValue;
        if (safeExit)
        {
            try
            {
                _EvalNode(cmd,space);
            }
            catch(...)
            {}
        }
        else _EvalNode(cmd,CseBltinModule);
    }
    // else, ignore exiting call
}

void Cse_ClearModContext(const TCseObj& CurrMod)
{   // remove none-reserved data
    TStolenObj ToFree;
    PEntryPoint pEntry = CurrMod->entry + 6;
    TEntryArray& dArray = CurrMod.dArray();
    while (dArray.enumItem(pEntry))
    {
        ToFree.bind(pEntry->value);
        pEntry->value = dummy;
    }
}

void Cse_ClearModule(const TCseObj& CurrMod, TBool safeExit)
{
    ASSERT_TRUE(CurrMod.isSpace());

    // run every item in bOnExit
    TCseObj bOnExit = CurrMod.quickGet(constOnExit);
    if (dummy != bOnExit && bOnExit.type() == dtBuff)
    {
        while (bOnExit.len() > 0)
        {
            TCseObj vItem = bOnExit.pop();
            if (vItem.type() != dtId)
                TryRunExitFunc(vItem,safeExit,CurrMod);
        }
    }

    // remove none-reserved data
    Cse_ClearModContext(CurrMod);

    // remove reserved data
    TCseObj bSubs = CurrMod.quickGet(constSubs);  // #5
    if (bSubs.type() == dtBuff) bSubs.clear();
    CurrMod.set(constSubs,CseNull);

    bSubs = CurrMod.quickGet(constVarList);       // #4
    if (bSubs.type() == dtBuff) bSubs.truncate(2);
    CurrMod.set(constVarList,CseNull);

    CurrMod.set(constBase,CseNull);               // #3
    CurrMod.set(constNameSpace,CseNull);          // #2
    CurrMod.set(constSpaceName,CseNull);          // #1
    CurrMod.set(constSpace,CseNull);              // #0
    CurrMod.clear();
}

void Cse_SetModule(const TCharArray& sModule, CseObj module)
{
    // __bltin__ and __main__ is special module, not need save to module list
    if (module == CseBltinModule || module == CseMainModule) return;

    TCseObj vName = TCseObj(TCharArray(sModule).upper());

    if (module == dummy) // remove module
    {
        int iLen = Cse_len(gCseModules);
        for (int iCount = 0; iCount < iLen; iCount++)
        {
            TCseObj v = gCseModules->bValue[iCount];
            if (v.type() == dtBuff && v.len() == 2 && v.sub(0) == vName)
            {
                TCseObj CurrMod = v.sub(1);
                if (CurrMod.isSpace())
                {
                    CseBuff_remove(gCseModules,iCount);
                    Cse_ClearModule(CurrMod,false);
                }
                break;
            }
        }
        return;
    }

    if (dtDict != CSE_TYPE(module)) return;
    while(true)
    {
        TBool OldExists = false;
        int iLen = Cse_len(gCseModules);
        for (int iCount = 0; iCount < iLen; iCount++)
        {
            TCseObj v = gCseModules->bValue[iCount];
            if (dtBuff == v.type() && v.len() == 2)
            {
                // if same module exists, adjust module name
                if (module == v.sub(1))
                {
                    if (v.sub(0) != vName)
                        v.sub(0) = vName;
                    return;
                }

                // if same name exists, remove old module value
                else if (v.sub(0) == vName)
                {
                    CseBuff_remove(gCseModules,iCount);
                    OldExists = true;
                    break;
                }
            }
        }
        if (! OldExists) break;
    }

    CseObj vMod = CseBuff_StolenAppend(gCseModules,CseBuff_new(0));
    CseBuff_append(vMod,vName);
    CseBuff_append(vMod,module);
}

STATIC TBool IsAbsoluteDir(const TXchar *sFile)
{
    for (int i = 0; i < 260; i++, sFile++)
    {
        TXchar ch = *sFile;
        if (ch == _T('\0')) break;

        if (ch == _T('/') || ch == _T('\\'))
        {
            if (i == 0)
               return true;
            else break;
        }
        else if (ch == _T(':'))  // ftp:// file:// C:/
            return true;
        else if (ch == _T('_') || (ch >= ('A') && ch <= _T('Z')) || (ch >= ('a') && ch <= _T('z')))
            continue;
        else break;
    }
    return false;
}

TBool Cse_SearchFile(TCharArray& ret, const TCharArray& sModule, const TCharArray& RefFile, TBool SysInc)
{
    // first, check absolute directory and DefaultDir
    if (sModule.isEmpty()) return false;

    if (IsAbsoluteDir(sModule.addr()))
    {   // Current file is absolute, no need search in PATH
        if (FileExists(sModule))
        {
            ret = sModule;
            return true;
        }
        else return false;
    }

    TBool WaitFindByRef = false;
    if ( !RefFile.isEmpty() && IsAbsoluteDir(RefFile) )
    {   // if "uses ModuleB" in ModuleA, try search ModuleA path
        if (SysInc)
            WaitFindByRef = true;  // #include <xxx.h>; find from lib paths first
        else
        {
            TCharArray sTmp = ExtractFileDir(RefFile) + CsePathSpliter + sModule;
            sTmp = NormalizeFileName(sTmp);
            if (FileExists(sTmp))
            {
                ret = sTmp;
                return true;
            }
        }
    }

    // then, try find from lib paths
    TCharArray sAppBase = ExtractFileDir(GetCurrExeFileName()) + CsePathSpliter;
    for (int iCount = 0; iCount < Cse_len(gCsePaths); iCount++)
    {
        CseObj v = gCsePaths->bValue[iCount];
        if (dtStr == CSE_TYPE(v))
        {
            TCharArray AName;
            Cse_BeStr(AName,v);
            int iLen = AName.len();
            
            TXchar ch;
            if (iLen == 0 || ((ch = AName[-1]) != _T('\\') && ch != _T('/')))
                AName += CsePathSpliter;

            if (IsAbsoluteDir(AName))
                AName = AName + sModule;
            else AName = sAppBase + AName + sModule;

            AName = NormalizeFileName(AName);
            if ( FileExists(AName) )
            {
                ret = AName;
                return true;
            }
        }
    }

    if (WaitFindByRef)
    {
        TCharArray sTmp = ExtractFileDir(RefFile) + CsePathSpliter + sModule;
        sTmp = NormalizeFileName(sTmp);
        if (FileExists(sTmp))
        {
            ret = sTmp;
            return true;
        }
    }
    return false;
}

CseObj Cse_LoadCsd(const TCharArray& sModule, const TCharArray& RefFile)
{
    TCharArray sFile;
    TCharArray sExt = ExtractFileExt(sModule).upper();

    if (sExt.isEmpty())  // first try *.csd, then try *.dll
        sFile = sModule + _T(".csd");
    else sFile = sModule;
    
    // first, try get from CSD/CSB/DLL directly
    CseObj ret = Cse_GetModule(sFile,false);
    if (NULL != ret) return ret;

    TCharArray sLocate;
    if (! Cse_SearchFile(sLocate,sFile,RefFile))
    {
        if (sExt.isEmpty())
        {
#if defined(__GNUC__) && !defined(__MINGW32__)
            sFile = sModule + _T(".so");  // under linux
#else
            sFile = sModule + _T(".dll");
#endif
            ret = Cse_GetModule(sFile,false);
            if (NULL != ret) return ret;
            Cse_SearchFile(sLocate,sFile,RefFile);
        }
    }

    if (sLocate.isEmpty())
        throw LOG_CSE_ERR(CSE_IO_ERR,_T("load module error:") + sModule);

    TDllFile dll(sLocate);
    if (dll.isLoaded())
    {
        CseObj (*LoadFunc)() = (CseObj (*)()) dll.getSymbol(_T("__entry__"));
        if (NULL != LoadFunc)
        {
            TCseObj RetMod = LoadFunc();
            if (! RetMod.isSpace())
                throw LOG_CSE_ERR(CSE_IO_ERR,_T("library format error:") + sLocate);

            void *h = dll.detach(); // detach dll handle
            CseBuff_StolenAppend(gCseDllHandles,CseInt_new((TInt) h));
            return RetMod;
        }
    }
    throw LOG_CSE_ERR(CSE_IO_ERR,_T("load library error:") + sLocate);
}

TBool Cse_UseModule(CseObj TargModule, CseObj SourModule)
{
    ASSERT_TRUE(dtDict == CSE_TYPE(TargModule) && dtDict == Cse_type(SourModule));

    PEntryPoint pEntry = TargModule->entry + 2;
    if (pEntry->key == constNameSpace && pEntry->value != NULL)
    {
        TCseObj modules = pEntry->value;
        if (modules.type() == dtBuff)
        {
            for (int i = 0; i < modules.len(); i++)
                if (modules->bValue[i] == SourModule)
                    return true;  // source module has exists

            // add imported module
            modules.append(SourModule);
            return true;
        }
    }
    
    return false;
}

void Cse_UnloadModules(TBool safeExit)
{
    // Run every top module's onExit-process
    TCseObj modules = gCseModules;
    while (modules.len() > 0)
    {
        TCseObj vMod = modules.pop();
        if (vMod.type() == dtBuff && vMod.len() == 2)
        {
            TCseObj CurrMod = vMod->bValue[1];
            if (CurrMod.type() == dtDict)
                Cse_ClearModule(CurrMod,safeExit);
        }
    }

    // Unload every DLL
    TCseObj Dlls = gCseDllHandles;
    while (Dlls.len() > 0)
    {
        TCseObj vItem = Dlls.pop();
        TDllFile::unloadLib((void *) vItem->iValue);
    }
}

CseObj Cse_NewModule(const TCharArray& sModule)
{
    CseObj ret = CseDict_new(16);
    TCseObj *pMod = (TCseObj *)&ret;
    
    pMod->set(constSpace,TCseObj::format(CSE_WEAK,ret));
    pMod->set(constSpaceName,TCseObj::format(CSE_ID,(TXchar*)sModule));
    pMod->set(constNameSpace,TCseObj::format(CSE_BUFF));
    pMod->set(constBase,CseNull);

    // default bVarList: [dummy,dEmpty]
    TCseObj bVarList = pMod->set(constVarList,TCseObj::format(_T("[v,v]"),dummy,CseEmptySpace));
    bVarList.append(CseEmptyTier); // symbol address list

    // default bSubMod: []
    pMod->set(constSubs,TCseObj::format(CSE_BUFF));

    // default bOnExit: []
    pMod->set(constOnExit,TCseObj::format(CSE_BUFF));

    ASSERT_TRUE((ret->entry + 6)->key == constOnExit); // hash of #6 is 6
    return ret;
}

void Cse_AddSymList(CseObj module, const TCharArray& name, TInt iFlag, TBool ErrWhenDup)
{
    ASSERT_TRUE(dtDict == CSE_TYPE(module) && module->entry[4].key == constVarList);

    CseObj bVarList = module->entry[4].value;
    ASSERT_TRUE(CSE_TYPE(bVarList) == dtBuff && Cse_len(bVarList) >= 3);
    CseObj tAddrList = bVarList->bValue[2];
    ASSERT_TRUE(CSE_TYPE(tAddrList) == dtTier);
    
    CseObj key = CseId_new(name);
    CseObj value = CseDict_EntryValue(gCseSymTable,key);
    if (value == NULL && ErrWhenDup)
    {
        Cse_DecRef(key);
        TCharArray sDesc = TCharArray::format(_T("symbol table(%s) already exists"),(TXchar *)name);
        throw LOG_CSE_ERR(CSE_VALUE_ERR,sDesc);
    }

    CseDict_StolenSet(gCseSymTable,key,CseWeak_new(module,Cse_len(tAddrList) | iFlag));
    Cse_DecRef(key);
}

int Cse_AddSymAddr(CseObj module, void *addr)
{
    ASSERT_TRUE(dtDict == CSE_TYPE(module) && module->entry[4].key == constVarList);

    CseObj bVarList = module->entry[4].value;
    ASSERT_TRUE(CSE_TYPE(bVarList) == dtBuff && Cse_len(bVarList) >= 3);
    CseObj tAddrList = bVarList->bValue[2];
    ASSERT_TRUE(CSE_TYPE(tAddrList) == dtTier);

    int ret;
    CseTier_append(tAddrList,(TInt)addr,&ret);
    return ret;
}

TBool Cse_AddSubModule(CseObj module, const TCharArray& name, CseObj SubModule)
{
    ASSERT_TRUE(dtDict == CSE_TYPE(module) && dtDict == Cse_type(SubModule));

    PEntryPoint pEntry = module->entry + 5;
    if (pEntry->key == constSubs && pEntry->value != NULL)
    {
        TCseObj ModList = pEntry->value;
        if (ModList.type() == dtBuff)
        {
            TBool hasAdd = false;
            for (int i = 1; i < ModList.len(); i += 2)
            {
                if (name == ModList[i-1].beStr())
                {   // same sub-module name exists
                    ModList[i] = SubModule;
                    hasAdd = true;
                    break;
                }
            }
            
            // add newly module
            TCseObj vId = TCseObj::format(CSE_ID,(TXchar*)name);
            if (! hasAdd)
            {
                CseBuff_append(pEntry->value,vId);  // alis name
                CseBuff_append(pEntry->value,vId);  // formal name
            }
            CseDict_set(module,vId,SubModule);
            return true;
        }
    }
    return false;
}

int Cse_AddExitFunc(CseObj module, void *func)
{
    ASSERT_TRUE(dtDict == CSE_TYPE(module));

    PEntryPoint pEntry = module->entry + 6;
    if (pEntry->key == constOnExit && pEntry->value != NULL && CSE_TYPE(pEntry->value) == dtBuff)
    {
        TCseObj vCmd = TCseObj::format(CSE_INSTANCE);
        vCmd.append(gCppVoidFunc);
        vCmd.append(TCseObj::format(CSE_WEAK,(TInt)func - 1));
        vCmd.append(TIntObj(1));

        int ret;
        TCseObj bOnExit = pEntry->value;
        bOnExit.bArray().add(vCmd,&ret);
        return ret;
    }
    return -1;
}

int Cse_AddModuleVar(CseObj module, CseObj var)
{
    ASSERT_TRUE(dtDict == CSE_TYPE(module));

    PEntryPoint pEntry = module->entry + 4;
    if (pEntry->key == constVarList && pEntry->value != NULL)
    {   // save special variable to module.#4
        TCseObj SymList = pEntry->value;
        if (SymList.type() == dtBuff)
        {
            int index;
            SymList.bArray().add(var,&index);
            return index;
        }
    }
    return -1;
}

TCseModule::TCseModule(const TCharArray& sModule, TBool OnlyTopLevel): TCseObj()
{
    CseObj mod = Cse_GetModule(sModule,OnlyTopLevel);
    if (mod == NULL)
    {
        TCseModule mod = create(sModule,true);
        m_data = Cse_IncRefEx(mod.m_data);
    }
    else m_data = Cse_IncRefEx(mod);
}

TCseModule::TCseModule(const TCseObj& module): TCseObj(module)
{
    CHECK_MSG(isSpace(),_T("module format error"));
}

TCharArray TCseModule::searchFile(const TCharArray& sModule, const TCharArray& RefFile, TBool SysInc)
{
    TCharArray ret;
    if (Cse_SearchFile(ret,sModule,RefFile,SysInc))
        return TCharArray(CUT_FROM,ret);
    else return CseEmptyStr;
}

TCseObj TCseModule::getModule(const TCharArray& sModule, TBool OnlyTopLevel)
{
    return Cse_GetModule(sModule,OnlyTopLevel);
}

void TCseModule::setModule(const TCharArray& sModule, const TCseObj& mod)
{   // if mod == dummy, means remove module
    Cse_SetModule(sModule,mod);
}

void *TCseModule::CFuncAddr(const TCseObj& vFunc)
{
    if (vFunc.type() == dtBuff && vFunc.len() == 2)
    {
        TCseObj v = vFunc.sub(1);
        if (v.type() == dtWeak)
            return (void *) v->iValue;        
    }
    else if (vFunc.isMapped() && vFunc.len() == 3)
    {
        TCseObj v = vFunc.sub(1);
        if (v.type() == dtWeak)
            return (void *) (v->iValue + vFunc.sub(2)->iValue);
    }
    throw LOG_CSE_ERR(CSE_VALUE_ERR,_T("illegal mapped object, get function address error"));
}

TCseModule TCseModule::create(const TCharArray& sModule, TBool regist)
{
    TStolenObj ret(Cse_NewModule(sModule));
    if (regist)
        Cse_SetModule(ExtractFileName(sModule),ret);
    return TCseObj((CseObj)ret);
}

TCseModule TCseModule::loadCsd(const TCharArray& sModule, const TCharArray& RefFile)
{
    return TCseObj(Cse_LoadCsd(sModule,RefFile));
}

void TCseModule::unloadAll(TBool safeExit)
{
    Cse_UnloadModules(safeExit);
}

TBool TCseModule::useModule(const TCseModule& module) const
{
    return Cse_UseModule(m_data,module.m_data);
}

void TCseModule::clear() const
{
    Cse_ClearModule(m_data,false);
}

const TCseObj& TCseModule::attrSet(const TCharArray& attr, const TCseObj& value) const
{
    TCseObj id = TCseObj::format(CSE_ID,(TXchar*)attr);
    return set(id,value);
}

TCseObj TCseModule::attrGet(const TCharArray& attr) const
{
    TCseObj id = TCseObj::format(CSE_ID,(TXchar*)attr);
    return get(id);
}

void TCseModule::addSymList(const TCharArray& name, TInt iFlag, TBool ErrWhenDup) const
{
    Cse_AddSymList(m_data,name,iFlag,ErrWhenDup);
}

int TCseModule::addSymAddr(void *addr) const
{
    return Cse_AddSymAddr(m_data,addr);
}

int TCseModule::addExitFunc(void *func) const
{
    return Cse_AddExitFunc(m_data,func);
}

int TCseModule::addModuleVar(const TCseObj& var) const
{
    return Cse_AddModuleVar(m_data,var);
}

TBool TCseModule::addSubModule(const TCharArray& name, const TCseObj& SubModule) const
{
    return Cse_AddSubModule(m_data,name,SubModule);
}

// Following define cdecl/stdcall/thiscall function call
//==============================================================================
void SetupArgAsTier(TIntArray& tArgs, const TObjArray& bArgs)
{
    int iNum = bArgs.len(); 
    CseObj *pObj = bArgs.addr();
    for (int i = 0; i < iNum; i++, pObj++)
    {
        CseObj vCurr = *pObj;
        int tp = CSE_TYPE(vCurr);

        if (tp == dtInt)
            tArgs.append(vCurr->iValue);           // TInt
        else if (tp == dtStr)
            tArgs.append((TInt)vCurr->sValue);     // TXchar*
        else if (tp == dtTier)
            tArgs.append((TInt)vCurr->tValue);     // TInt*
        else if (tp == dtWint)
        {
            if (sizeof(TInt) == sizeof(TWint))
                tArgs.append(vCurr->iValue);       // TWint
            else
            {
                ASSERT_TRUE(2 * sizeof(TInt) == sizeof(TWint));
                tArgs.append(vCurr->iValue);       // TWint
                tArgs.append(vCurr->iFlag);
            }
        }
        else if (tp == dtFloat)
        {
            if (sizeof(TInt) == sizeof(TDouble))
                tArgs.append(vCurr->iValue);       // TDouble
            else
            {
                ASSERT_TRUE(2 * sizeof(TInt) == sizeof(TDouble));
                tArgs.append(vCurr->iValue);       // TDouble
                tArgs.append(vCurr->iFlag);
            }
        }
        else if (tp == dtBuff)
            tArgs.append((TInt)vCurr->bValue);     // CseObj*
        else if (tp == dtDict)
            tArgs.append((TInt)vCurr->entry);      // PEntryPoint
        else throw LOG_CSE_ERR(CSE_ARGS_ERR,TCharArray::format(_T("argument %d convert from TCseObj meet error"),i+1));
    }
}

TInt Cse_CallCdecl(void *pFunc, const TObjArray& bArgs)
{
    TIntArray tArgs;
    SetupArgAsTier(tArgs,bArgs);

    int iNum = tArgs.len();
    if (iNum > 16) throw LOG_CSE_ERR(CSE_ARGS_ERR,_T("too many arguments"));

    TInt *args = tArgs.addr();
    if (iNum <= 8)
    {
        if (iNum <= 4)
        {
            if (iNum <= 2)
            {
                if (iNum == 0)
                {
                    TInt (*ObjFunc)() = (TInt (*)())pFunc;
                    return ObjFunc();
                }
                else if (iNum == 1)
                {
                    TInt (*ObjFunc)(TInt) = (TInt (*)(TInt))pFunc;
                    return ObjFunc(args[0]);
                }
                else // iNum == 2
                {
                    TInt (*ObjFunc)(TInt,TInt) = (TInt (*)(TInt,TInt))pFunc;
                    return ObjFunc(args[0],args[1]);
                }
            }
            else if (iNum == 3)
            {
                TInt (*ObjFunc)(TInt,TInt,TInt) = (TInt (*)(TInt,TInt,TInt))pFunc;
                return ObjFunc(args[0],args[1],args[2]);
            }
            else  // iNum == 4
            {
                TInt (*ObjFunc)(TInt,TInt,TInt,TInt) = (TInt (*)(TInt,TInt,TInt,TInt))pFunc;
                return ObjFunc(args[0],args[1],args[2],args[3]);
            }
        }
        else if (iNum <= 6)
        {
            if (iNum == 5)
            {
                TInt (*ObjFunc)(TInt,TInt,TInt,TInt,TInt) = (TInt (*)(TInt,TInt,TInt,TInt,TInt))pFunc;
                return ObjFunc(args[0],args[1],args[2],args[3],args[4]);
            }
            else  // iNum == 6
            {
                TInt (*ObjFunc)(TInt,TInt,TInt,TInt,TInt,TInt) = (TInt (*)(TInt,TInt,TInt,TInt,TInt,TInt))pFunc;
                return ObjFunc(args[0],args[1],args[2],args[3],args[4],args[5]);
            }
        }
        else if (iNum == 7)
        {
            TInt (*ObjFunc)(TInt,TInt,TInt,TInt,TInt,TInt,TInt) = (TInt (*)(TInt,TInt,TInt,TInt,TInt,TInt,TInt))pFunc;
            return ObjFunc(args[0],args[1],args[2],args[3],args[4],args[5],args[6]);
        }
        else  // iNum == 8
        {
            TInt (*ObjFunc)(TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt) = (TInt (*)(TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt))pFunc;
            return ObjFunc(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7]);
        }
    }
    else if (iNum <= 12)
    {
        if (iNum <= 10)
        {
            if (iNum == 9)
            {
                TInt (*ObjFunc)(TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt) = (TInt (*)(TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt))pFunc;
                return ObjFunc(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8]);
            }
            else  // iNum == 10
            {
                TInt (*ObjFunc)(TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt) = (TInt (*)(TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt))pFunc;
                return ObjFunc(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],args[9]);
            }
        }
        else if (iNum == 11)
        {
            TInt (*ObjFunc)(TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt) = (TInt (*)(TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt))pFunc;
            return ObjFunc(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],args[9],args[10]);
        }
        else  // iNum == 12
        {
            TInt (*ObjFunc)(TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt) = (TInt (*)(TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt))pFunc;
            return ObjFunc(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],args[9],args[10],args[11]);
        }
    }
    else if (iNum <= 14)
    {
        if (iNum == 13)
        {
            TInt (*ObjFunc)(TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt) = (TInt (*)(TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt))pFunc;
            return ObjFunc(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],args[9],args[10],args[11],args[12]);
        }
        else  // iNum == 14
        {
            TInt (*ObjFunc)(TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt) = (TInt (*)(TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt))pFunc;
            return ObjFunc(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],args[9],args[10],args[11],args[12],args[13]);
        }
    }
    else if (iNum == 15)
    {
        TInt (*ObjFunc)(TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt) = (TInt (*)(TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt))pFunc;
        return ObjFunc(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],args[9],args[10],args[11],args[12],args[13],args[14]);
    }
    else   // iNum == 16
    {
        TInt (*ObjFunc)(TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt) = (TInt (*)(TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt))pFunc;
        return ObjFunc(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],args[9],args[10],args[11],args[12],args[13],args[14],args[15]);
    }
}

TInt Cse_CallStdcall(void *pFunc, const TObjArray& bArgs)
{
    TIntArray tArgs;
    SetupArgAsTier(tArgs,bArgs);

    int iNum = tArgs.len();
    if (iNum > 16) throw LOG_CSE_ERR(CSE_ARGS_ERR,_T("too many arguments"));

    TInt *args = tArgs.addr();
    if (iNum <= 8)
    {
        if (iNum <= 4)
        {
            if (iNum <= 2)
            {
                if (iNum == 0)
                {
                    TInt (CSE_STDCALL *ObjFunc)() = (TInt (CSE_STDCALL *)())pFunc;
                    return ObjFunc();
                }
                else if (iNum == 1)
                {
                    TInt (CSE_STDCALL *ObjFunc)(TInt) = (TInt (CSE_STDCALL *)(TInt))pFunc;
                    return ObjFunc(args[0]);
                }
                else // iNum == 2
                {
                    TInt (CSE_STDCALL *ObjFunc)(TInt,TInt) = (TInt (CSE_STDCALL *)(TInt,TInt))pFunc;
                    return ObjFunc(args[0],args[1]);
                }
            }
            else if (iNum == 3)
            {
                TInt (CSE_STDCALL *ObjFunc)(TInt,TInt,TInt) = (TInt (CSE_STDCALL *)(TInt,TInt,TInt))pFunc;
                return ObjFunc(args[0],args[1],args[2]);
            }
            else  // iNum == 4
            {
                TInt (CSE_STDCALL *ObjFunc)(TInt,TInt,TInt,TInt) = (TInt (CSE_STDCALL *)(TInt,TInt,TInt,TInt))pFunc;
                return ObjFunc(args[0],args[1],args[2],args[3]);
            }
        }
        else if (iNum <= 6)
        {
            if (iNum == 5)
            {
                TInt (CSE_STDCALL *ObjFunc)(TInt,TInt,TInt,TInt,TInt) = (TInt (CSE_STDCALL *)(TInt,TInt,TInt,TInt,TInt))pFunc;
                return ObjFunc(args[0],args[1],args[2],args[3],args[4]);
            }
            else  // iNum == 6
            {
                TInt (CSE_STDCALL *ObjFunc)(TInt,TInt,TInt,TInt,TInt,TInt) = (TInt (CSE_STDCALL *)(TInt,TInt,TInt,TInt,TInt,TInt))pFunc;
                return ObjFunc(args[0],args[1],args[2],args[3],args[4],args[5]);
            }
        }
        else if (iNum == 7)
        {
            TInt (CSE_STDCALL *ObjFunc)(TInt,TInt,TInt,TInt,TInt,TInt,TInt) = (TInt (CSE_STDCALL *)(TInt,TInt,TInt,TInt,TInt,TInt,TInt))pFunc;
            return ObjFunc(args[0],args[1],args[2],args[3],args[4],args[5],args[6]);
        }
        else  // iNum == 8
        {
            TInt (CSE_STDCALL *ObjFunc)(TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt) = (TInt (CSE_STDCALL *)(TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt))pFunc;
            return ObjFunc(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7]);
        }
    }
    else if (iNum <= 12)
    {
        if (iNum <= 10)
        {
            if (iNum == 9)
            {
                TInt (CSE_STDCALL *ObjFunc)(TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt) = (TInt (CSE_STDCALL *)(TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt))pFunc;
                return ObjFunc(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8]);
            }
            else  // iNum == 10
            {
                TInt (CSE_STDCALL *ObjFunc)(TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt) = (TInt (CSE_STDCALL *)(TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt))pFunc;
                return ObjFunc(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],args[9]);
            }
        }
        else if (iNum == 11)
        {
            TInt (CSE_STDCALL *ObjFunc)(TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt) = (TInt (CSE_STDCALL *)(TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt))pFunc;
            return ObjFunc(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],args[9],args[10]);
        }
        else  // iNum == 12
        {
            TInt (CSE_STDCALL *ObjFunc)(TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt) = (TInt (CSE_STDCALL *)(TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt))pFunc;
            return ObjFunc(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],args[9],args[10],args[11]);
        }
    }
    else if (iNum <= 14)
    {
        if (iNum == 13)
        {
            TInt (CSE_STDCALL *ObjFunc)(TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt) = (TInt (CSE_STDCALL *)(TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt))pFunc;
            return ObjFunc(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],args[9],args[10],args[11],args[12]);
        }
        else  // iNum == 14
        {
            TInt (CSE_STDCALL *ObjFunc)(TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt) = (TInt (CSE_STDCALL *)(TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt))pFunc;
            return ObjFunc(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],args[9],args[10],args[11],args[12],args[13]);
        }
    }
    else if (iNum == 15)
    {
        TInt (CSE_STDCALL *ObjFunc)(TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt) = (TInt (CSE_STDCALL *)(TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt))pFunc;
        return ObjFunc(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],args[9],args[10],args[11],args[12],args[13],args[14]);
    }
    else   // iNum == 16
    {
        TInt (CSE_STDCALL *ObjFunc)(TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt) = (TInt (CSE_STDCALL *)(TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt))pFunc;
        return ObjFunc(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],args[9],args[10],args[11],args[12],args[13],args[14],args[15]);
    }
}

class CSimObjCall { };
typedef void (CSimObjCall::* SIM_THISCALL)();

TInt Cse_CallThiscall(void *pFunc, void *pSelf, const TObjArray& bArgs)
{
    TIntArray tArgs;
    SetupArgAsTier(tArgs,bArgs);

    union {
        SIM_THISCALL ptr;
        void *addr;
    } func;
    func.addr = pFunc;

    int iNum = tArgs.len();
    if (iNum > 16) throw LOG_CSE_ERR(CSE_ARGS_ERR,_T("too many arguments"));

    TInt *args = tArgs.addr();
    if (iNum <= 8)
    {
        if (iNum <= 4)
        {
            if (iNum <= 2)
            {
                if (iNum == 0)
                {
                    TInt (CSimObjCall::* ObjFunc)() = (TInt (CSimObjCall::*)()) func.ptr;
                    return (((CSimObjCall *)pSelf)->*ObjFunc)();
                }
                else if (iNum == 1)
                {
                    TInt (CSimObjCall::* ObjFunc)(TInt) = (TInt (CSimObjCall::*)(TInt)) func.ptr;
                    return (((CSimObjCall *)pSelf)->*ObjFunc)(args[0]);
                }
                else // iNum == 2
                {
                    TInt (CSimObjCall::* ObjFunc)(TInt,TInt) = (TInt (CSimObjCall::*)(TInt,TInt)) func.ptr;
                    return (((CSimObjCall *)pSelf)->*ObjFunc)(args[0],args[1]);
                }
            }
            else if (iNum == 3)
            {
                TInt (CSimObjCall::* ObjFunc)(TInt,TInt,TInt) = (TInt (CSimObjCall::*)(TInt,TInt,TInt)) func.ptr;
                return (((CSimObjCall *)pSelf)->*ObjFunc)(args[0],args[1],args[2]);
            }
            else  // iNum == 4
            {
                TInt (CSimObjCall::* ObjFunc)(TInt,TInt,TInt,TInt) = (TInt (CSimObjCall::*)(TInt,TInt,TInt,TInt)) func.ptr;
                return (((CSimObjCall *)pSelf)->*ObjFunc)(args[0],args[1],args[2],args[3]);
            }
        }
        else if (iNum <= 6)
        {
            if (iNum == 5)
            {
                TInt (CSimObjCall::* ObjFunc)(TInt,TInt,TInt,TInt,TInt) = (TInt (CSimObjCall::*)(TInt,TInt,TInt,TInt,TInt)) func.ptr;
                return (((CSimObjCall *)pSelf)->*ObjFunc)(args[0],args[1],args[2],args[3],args[4]);
            }
            else  // iNum == 6
            {
                TInt (CSimObjCall::* ObjFunc)(TInt,TInt,TInt,TInt,TInt,TInt) = (TInt (CSimObjCall::*)(TInt,TInt,TInt,TInt,TInt,TInt)) func.ptr;
                return (((CSimObjCall *)pSelf)->*ObjFunc)(args[0],args[1],args[2],args[3],args[4],args[5]);
            }
        }
        else if (iNum == 7)
        {
            TInt (CSimObjCall::* ObjFunc)(TInt,TInt,TInt,TInt,TInt,TInt,TInt) = (TInt (CSimObjCall::*)(TInt,TInt,TInt,TInt,TInt,TInt,TInt)) func.ptr;
            return (((CSimObjCall *)pSelf)->*ObjFunc)(args[0],args[1],args[2],args[3],args[4],args[5],args[6]);
        }
        else  // iNum == 8
        {
            TInt (CSimObjCall::* ObjFunc)(TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt) = (TInt (CSimObjCall::*)(TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt)) func.ptr;
            return (((CSimObjCall *)pSelf)->*ObjFunc)(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7]);
        }
    }
    else if (iNum <= 12)
    {
        if (iNum <= 10)
        {
            if (iNum == 9)
            {
                TInt (CSimObjCall::* ObjFunc)(TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt) = (TInt (CSimObjCall::*)(TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt)) func.ptr;
                return (((CSimObjCall *)pSelf)->*ObjFunc)(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8]);
            }
            else  // iNum == 10
            {
                TInt (CSimObjCall::* ObjFunc)(TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt) = (TInt (CSimObjCall::*)(TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt)) func.ptr;
                return (((CSimObjCall *)pSelf)->*ObjFunc)(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],args[9]);
            }
        }
        else if (iNum == 11)
        {
            TInt (CSimObjCall::* ObjFunc)(TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt) = (TInt (CSimObjCall::*)(TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt)) func.ptr;
            return (((CSimObjCall *)pSelf)->*ObjFunc)(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],args[9],args[10]);
        }
        else  // iNum == 12
        {
            TInt (CSimObjCall::* ObjFunc)(TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt) = (TInt (CSimObjCall::*)(TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt)) func.ptr;
            return (((CSimObjCall *)pSelf)->*ObjFunc)(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],args[9],args[10],args[11]);
        }
    }
    else if (iNum <= 14)
    {
        if (iNum == 13)
        {
            TInt (CSimObjCall::* ObjFunc)(TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt) = (TInt (CSimObjCall::*)(TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt)) func.ptr;
            return (((CSimObjCall *)pSelf)->*ObjFunc)(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],args[9],args[10],args[11],args[12]);
        }
        else  // iNum == 14
        {
            TInt (CSimObjCall::* ObjFunc)(TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt) = (TInt (CSimObjCall::*)(TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt)) func.ptr;
            return (((CSimObjCall *)pSelf)->*ObjFunc)(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],args[9],args[10],args[11],args[12],args[13]);
        }
    }
    else if (iNum == 15)
    {
        TInt (CSimObjCall::* ObjFunc)(TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt) = (TInt (CSimObjCall::*)(TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt)) func.ptr;
        return (((CSimObjCall *)pSelf)->*ObjFunc)(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],args[9],args[10],args[11],args[12],args[13],args[14]);
    }
    else   // iNum == 16
    {
        TInt (CSimObjCall::* ObjFunc)(TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt) = (TInt (CSimObjCall::*)(TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt,TInt)) func.ptr;
        return (((CSimObjCall *)pSelf)->*ObjFunc)(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],args[9],args[10],args[11],args[12],args[13],args[14],args[15]);
    }
}

// Following define module init and exit
//==============================================================================
void SetupDefaultPath(void)
{   // add current EXE file path
    TCharArray AppDir = ExtractFileDir(GetCurrExeFileName());
    CseBuff_StolenAppend(gCsePaths,CseStr_new(AppDir));
    CseBuff_StolenAppend(gCsePaths,CseStr_new(AppDir + CsePathSpliter + _T("source")));
    CseBuff_StolenAppend(gCsePaths,CseStr_new(AppDir + CsePathSpliter + _T("testcase")));

    TCharArray sLibDir = Cse_GetHomeDir();

    if (! sLibDir.isEmpty())
    {
        CseBuff_StolenAppend(gCsePaths,CseStr_new(sLibDir));
        
        TCharArray sOut;
        if (SearchSubDirs(sOut,sLibDir))
        {
            TXchar *pOutList = sOut.addr();
            size_t i = 0, iLen = sOut.len();

            while (i < iLen)
            {
                TXchar *sItem = pOutList + i;
                TCharArray s = sItem;

                if (! s.isEmpty())
                    CseBuff_StolenAppend(gCsePaths,CseStr_new(s));
                i += s.len() + 1;
            }
        }
    }
}

#if (defined(__VISUALC__) && !defined(WINCE)) || defined(__MINGW32__)
CseObj Cse_BeStr_(CseObj value)
{   // void Cse_BeStr(TCharArray& ret, CseObj value);
    TCharArray ret;
    Cse_BeStr(ret,value);
    return CseStr_NewEx(ret);
}

CseObj CseStr_new_(TXchar ch, int n)
{
    TCharArray s(ch,n);
    return CseStr_NewEx(s);
}

void CseStr_AssignEx_(CseObj TargStr, TXchar *sDesc, int n)
{
    TCharArray s(sDesc,n);
    CseStr_assign(TargStr,s);
}

void CseStr_joinEx_(CseObj TargStr, TXchar *SourStr, int iLen, int index)
{   // void CseStr_join(CseObj TargStr, const TCharArray& SourStr, int index)
    TCharArray s(SourStr,iLen);
    CseStr_join(TargStr,s,index);
}

PEntryPoint CseDict_IdEntry_(CseObj dict, CseObj Id)
{
    ASSERT_TRUE(CSE_TYPE(Id) == dtId);
    TCharArray *s = (TCharArray *) &Id->sValue;
    return CseDict_IdEntry(dict,*s,Id->hash);
}

PEntryPoint CseDict_IntEntry_(CseObj dict, CseObj iObj)
{
    ASSERT_TRUE(CSE_TYPE(iObj) == dtInt);

    TEntryArray *EntryArray = (TEntryArray *) &dict->entry;
    return EntryArray->intEntry(iObj->iValue);
}

CseObj CseDict_EntryValue_(CseObj dict, CseObj key)
{
    TEntryArray *EntryArray = (TEntryArray *) &dict->entry;
    CseObj v = EntryArray->get(key);
    if (v == dummy)
        return NULL;
    else return v;
}

CseObj _CseId_new(TXchar *sDesc, int n)
{
    TCharArray s(sDesc,n);
    return CseId_NewEx(s);
}

TBool CseRegist_exist_(const TXchar *key)
{   // TBool CseRegist_exist(const TCharArray& key)
    return CseRegist_exist(key);
}

CseObj CseRegist_get_(const TXchar *key)
{   // CseObj CseRegist_get(const TCharArray& key)
    return CseRegist_get(key);
}

CseObj CseRegist_StolenSet_(const TXchar *key, CseObj value)
{   // CseObj CseRegist_StolenSet(const TCharArray& key, CseObj value)
    return CseRegist_StolenSet(key,value);
}

CseObj CseRegist_set_(const TXchar *key, CseObj value)
{   // CseObj CseRegist_set(const TCharArray& key, CseObj value)
    return CseRegist_set(key,value);
}

void CseRegist_delete_(const TXchar *key)
{   // void CseRegist_delete(const TCharArray& key)
    CseRegist_delete(key);
}
#endif

void CseModule_SetAppArg()
{
    ASSERT_TRUE(sizeof(TInt) == sizeof(void*));

    int iLen = Cse_len(gCseArguments);
    CseObj ArgList = CseTier_new(iLen+1);
    for (int i = 0; i < iLen; i++)
        ArgList->tValue[i] = (TInt) gCseArguments->bValue[i]->sValue;
    ArgList->tValue[iLen] = 0;

    CseRegist_StolenSet(_T("KERNEL/ARGS_LIST"),ArgList);
}

void CseModules_SetArg(int argc, TXchar **argv)
{
    CseBuff_clear(gCseArguments);
    for (int i = 0; i < argc; i++)
        CseBuff_StolenAppend(gCseArguments,CseStr_new(argv[i]));
    CseModule_SetAppArg();
}

void CseModules_SetArgA(int argc, TChar **argv)
{
    CseBuff_clear(gCseArguments);
    for (int i = 0; i < argc; i++)
    {
        TCharArray s = Cse_StrFromAnsi(argv[i]);
        CseBuff_StolenAppend(gCseArguments,CseStr_NewEx(s));
    }
    CseModule_SetAppArg();
}

void CseModules_SetArgW(int argc, TWchar **argv)
{
    CseBuff_clear(gCseArguments);
    for (int i = 0; i < argc; i++)
    {
        TCharArray s = Cse_StrFromUnicode(argv[i]);
        CseBuff_StolenAppend(gCseArguments,CseStr_NewEx(s));
    }
    CseModule_SetAppArg();
}

void CseModules_init()
{
    ModuleInitCount++;
    if (ModuleInitCount > 1) return;  // only execute at first time
    
#if defined(__GNUC__) && !defined(__MINGW32__)
    cpu_set_t mask;
    CPU_ZERO(&mask);
    CPU_SET(0,&mask);
    sched_setaffinity(0,sizeof(mask),&mask);

#else
  #ifndef WINCE
    SetProcessAffinityMask(GetCurrentProcess(),1);
  #endif
#endif

    CseCharBuffLock  = new TCriticalSection();
    CseIntBuffLock   = new TCriticalSection();
    CseObjBuffLock   = new TCriticalSection();
    CseEntryBuffLock = new TCriticalSection();
    CseRecycleLock   = new TCriticalSection();

    Cse_LastErrName  = new TCharArray();
    Cse_LastErrDesc  = new TCharArray();

    if (! ModuleIsInit)
    {
        ModuleIsInit = true;

        BaseTypes_init();
        
        constSpace      = CseRegist_StolenHold(CseId_new(_T("#0"))); // __space__
        constSpaceName  = CseRegist_StolenHold(CseId_new(_T("#1"))); // __name__
        constNameSpace  = CseRegist_StolenHold(CseId_new(_T("#2"))); // __namespace__
        constBase       = CseRegist_StolenHold(CseId_new(_T("#3"))); // __base__
        constVarList    = CseRegist_StolenHold(CseId_new(_T("#4"))); // __symbol__
        constSubs       = CseRegist_StolenHold(CseId_new(_T("#5"))); // __init__
        constOnExit     = CseRegist_StolenHold(CseId_new(_T("#6"))); // __del__

        // initial system environment
        gCseDllHandles  = CseRegist_StolenHold(CseBuff_new(0));
        gCseSymTable    = CseRegist_StolenSet(_T("KERNEL/SYM_TABLE"),CseDict_new());
        gCsePaths       = CseRegist_StolenSet(_T("KERNEL/PATHS"),CseBuff_new(0));
        gCseArguments   = CseRegist_StolenSet(_T("KERNEL/ARGS"),CseBuff_new(0));
        gCseOnExit      = CseRegist_StolenSet(_T("KERNEL/ON_EXIT"),CseBuff_new(0));
        gCppVoidFunc    = CseRegist_StolenSet(_T("KERNEL/VOID_FUNC"),CseBuff_new(0));
        gScriptEvalFunc = CseRegist_StolenSet(_T("KERNEL/EVALNODE"),CseInt_new(0));
        gScriptCompFunc = CseRegist_StolenSet(_T("KERNEL/COMPILE_FUNC"),CseInt_new(0));
        gCppStrType     = CseRegist_StolenSet(_T("KERNEL/CPPSTR_TYPE"),CseDict_new());
                          CseRegist_StolenSet(_T("KERNEL/RUN_STATE"),CseInt_new(0));
        SetupDefaultPath();

        CseRegist_StolenSet(_T("KERNEL/EXPT_TRANS"),CseBuff_new(0));
        CseRegist_StolenSet(_T("KERNEL/USE_HOST"),CseInt_new(1));

        // create CSE register interface: CseRegister
        CseRegister     = new TCseRegister();

        // create CSE module interface: CseModules
        gCseModules     = CseBuff_new(0);
        CseBltinModule  = Cse_NewModule(_T("__bltin__")); // special builtin module
        CseMainModule   = Cse_NewModule(_T("__main__"));  // special builtin module

        TIntArray *pArray = &(CseRegister->set(_T("KERNEL/KERNEL_API"),TCseObj::format(CSE_TIER)).tArray());
        pArray->append((TInt) CSE_API_VERSION);                // 0
        pArray->append((TInt) CSE_FEATURE_FLAG);               // 1
        pArray->append((TInt) 0);                              // reserved: 2
        pArray->append((TInt) 0);                              // reserved: 3

#if (defined(__VISUALC__) && !defined(WINCE)) || defined(__MINGW32__)
        // regist C style API, prepared for other language system, such as delphi
        //-------------------------------------
        pArray->append((TInt) &CseDict_IdEntry_);              // 4
        pArray->append((TInt) &CseDict_IntEntry_);             // 5

        pArray->append((TInt) dummy);                          // 6
        pArray->append((TInt) CseNull);                        // 7
        pArray->append((TInt) CseBltinModule);                 // 8
        pArray->append((TInt) CseMainModule);                  // 9
        pArray->append((TInt) CseEmptySpace);                  // 10
        pArray->append((TInt) CseThreadStacks);                // 11
        
        pArray->append((TInt) &Cse_CloseRefCheck);             // 12
        pArray->append((TInt) &Cse_free);                      // 13
        pArray->append((TInt) &Cse_GetTypeName);               // 14

        //-------------------------------------
        pArray->append((TInt) &Cse_IncRef);                    // 15
        pArray->append((TInt) &Cse_DecRef);                    // 16
        pArray->append((TInt) &Cse_IncRefEx);                  // 17
        pArray->append((TInt) &Cse_RefCount);                  // 18

        pArray->append((TInt) &Cse_type);                      // 19
        pArray->append((TInt) &Cse_len);                       // 20
        pArray->append((TInt) &Cse_FixSize);                   // 21
        pArray->append((TInt) &Cse_hash);                      // 22
        pArray->append((TInt) &Cse_ObjComp);                   // 23
        pArray->append((TInt) &Cse_compare);                   // 24
        pArray->append((TInt) &Cse_equal);                     // 25

        pArray->append((TInt) &Cse_GetFlag);                   // 26
        pArray->append((TInt) &Cse_SetFlag);                   // 27
        pArray->append((TInt) &Cse_OptionOn);                  // 28
        pArray->append((TInt) &Cse_SetOption);                 // 29
        pArray->append((TInt) &Cse_ClearOption);               // 30

        pArray->append((TInt) &Cse_unlink);                    // 31
        pArray->append((TInt) &Cse_BeStr_);                    // 32
        pArray->append((TInt) &Cse_StrEx);                     // 33
        pArray->append((TInt) 0);                              // 34, reserved

        //-------------------------------------
        pArray->append((TInt) &CseInt_new);                    // 35
        pArray->append((TInt) &CseWint_new);                   // 36
        pArray->append((TInt) &CseFloat_new);                  // 37

        CseObj (*_StrNew)(const TXchar *,int) = &CseStr_new;
        pArray->append((TInt) _StrNew);                        // 38
        pArray->append((TInt) &CseStr_new_);                   // 39
        
        pArray->append((TInt) &CseStr_append);                 // 40
        pArray->append((TInt) &CseStr_get);                    // 41
        pArray->append((TInt) &CseStr_set);                    // 42
        pArray->append((TInt) &CseStr_insert);                 // 43
        pArray->append((TInt) &CseStr_slice);                  // 44
        pArray->append((TInt) &CseStr_remove);                 // 45
        pArray->append((TInt) &CseStr_clear);                  // 46
        pArray->append((TInt) &CseStr_AssignEx_);              // 47

        void (*_StrAssign)(CseObj,CseObj) = &CseStr_assign;
        pArray->append((TInt) _StrAssign);                     // 48
        void (*_StrJoin)(CseObj,CseObj,int) = &CseStr_join;
        pArray->append((TInt) _StrJoin);                       // 49
        pArray->append((TInt) &CseStr_joinEx_);                // 50
        pArray->append((TInt) &CseStr_SortAdd);                // 51
        pArray->append((TInt) &CseStr_sort);                   // 52
        pArray->append((TInt) &CseStr_upper);                  // 53
        pArray->append((TInt) &CseStr_lower);                  // 54
        pArray->append((TInt) &CseStr_trim);                   // 55
        pArray->append((TInt) &CseStr_TrimLeft);               // 56
        pArray->append((TInt) &CseStr_TrimRight);              // 57
        pArray->append((TInt) &CseStr_truncate);               // 58
        pArray->append((TInt) &CseStr_hash);                   // 59
        
        int (*_StrFind1)(CseObj,TXchar,TBool) = &CseStr_find;
        int (*_StrFind2)(CseObj,const TXchar *,int) = &CseStr_find;
        pArray->append((TInt) _StrFind1);                      // 60
        pArray->append((TInt) _StrFind2);                      // 61
        pArray->append((TInt) &CseStr_ToInt);                  // 62
        pArray->append((TInt) &CseStr_ToWint);                 // 63
        pArray->append((TInt) &CseStr_ToDouble);               // 64

        //-------------------------------------
        CseObj (*_TierNew)(int) = &CseTier_new;
        pArray->append((TInt) _TierNew);                       // 65
        pArray->append((TInt) &CseTier_append);                // 66
        pArray->append((TInt) &CseTier_get);                   // 67
        pArray->append((TInt) &CseTier_set);                   // 68
        pArray->append((TInt) &CseTier_insert);                // 69
        pArray->append((TInt) &CseTier_slice);                 // 70
        pArray->append((TInt) &CseTier_remove);                // 71
        pArray->append((TInt) &CseTier_clear);                 // 72
        
        void (*_TierAssign)(CseObj,CseObj) = &CseTier_assign;
        pArray->append((TInt) _TierAssign);                    // 73
        void (*_TierJoin)(CseObj,CseObj,int) = &CseTier_join;
        pArray->append((TInt) _TierJoin);                      // 74
        pArray->append((TInt) &CseTier_SortAdd);               // 75
        pArray->append((TInt) &CseTier_sort);                  // 76
        pArray->append((TInt) &CseTier_truncate);              // 77

        //-------------------------------------
        CseObj (*_BuffNew)(int) = &CseBuff_new;
        pArray->append((TInt) _BuffNew);                       // 78
        pArray->append((TInt) &CseBuff_StolenAppend);          // 79
        pArray->append((TInt) &CseBuff_append);                // 80
        pArray->append((TInt) &CseBuff_get);                   // 81
        pArray->append((TInt) &CseBuff_set);                   // 82
        pArray->append((TInt) &CseBuff_insert);                // 83
        pArray->append((TInt) &CseBuff_slice);                 // 84
        pArray->append((TInt) &CseBuff_remove);                // 85
        pArray->append((TInt) &CseBuff_clear);                 // 86

        void (*_BuffAssign)(CseObj,CseObj) = &CseBuff_assign;
        pArray->append((TInt) _BuffAssign);                    // 87
        void (*_BuffJoin)(CseObj,CseObj,int) = &CseBuff_join;
        pArray->append((TInt) _BuffJoin);                      // 88
        pArray->append((TInt) &CseBuff_SortAdd);               // 89
        pArray->append((TInt) &CseBuff_sort);                  // 90
        pArray->append((TInt) &CseBuff_truncate);              // 91
        pArray->append((TInt) &CseBuff_ToNotator);             // 92

        //-------------------------------------
        CseObj (*_DictNew)(int) = &CseDict_new;
        pArray->append((TInt) _DictNew);                       // 93
        pArray->append((TInt) &CseDict_EntryValue_);           // 94
        pArray->append((TInt) &CseDict_StolenSet);             // 95
        pArray->append((TInt) &CseDict_set);                   // 96
        pArray->append((TInt) &CseDict_SetEx);                 // 97
        pArray->append((TInt) &CseDict_clear);                 // 98

        void (*_DictAssign)(CseObj,CseObj) = &CseDict_assign;
        pArray->append((TInt) _DictAssign);                    // 99
        void (*_DictJoin)(CseObj,CseObj) = &CseDict_join;
        pArray->append((TInt) _DictJoin);                      // 100
        pArray->append((TInt) &CseDict_StolenBind);            // 101
        pArray->append((TInt) &CseDict_bind);                  // 102
        pArray->append((TInt) &CseDict_GetBinding);            // 103
        pArray->append((TInt) &CseDict_enumItem);              // 104

        //-------------------------------------
        pArray->append((TInt) &CseNotator_new);                // 105
        pArray->append((TInt) &CseStrong_new);                 // 106
        pArray->append((TInt) &CseStrong_StolenSet);           // 107
        pArray->append((TInt) &CseStrong_set);                 // 108

        pArray->append((TInt) &_CseId_new);                    // 109
        pArray->append((TInt) &CseWeak_new);                   // 110
        pArray->append((TInt) &CseInstance_new);               // 111

        //-------------------------------------
        pArray->append((TInt) &CseRegist_exist_);              // 112
        pArray->append((TInt) &CseRegist_get_);                // 113
        pArray->append((TInt) &CseRegist_StolenSet_);          // 114
        pArray->append((TInt) &CseRegist_set_);                // 115
        pArray->append((TInt) &CseRegist_delete_);             // 116
        
        pArray->append((TInt) &CseRegist_hold);                // 117
        pArray->append((TInt) &CseRegist_StolenHold);          // 118
#endif
    }
}

void CseModules_exit()
{
    extern void Cse_CleanRecycle();

    ModuleInitCount--;
    if (ModuleInitCount > 0) return;  // only execute at last time
    
    if (ModuleIsInit)
    {
        ModuleIsInit = false;

        Cse_ClearModContext(CseMainModule);
        TCseModule::unloadAll(true);
        Cse_ClearModContext(CseBltinModule);

        Cse_free(gCseModules,true);
        delete CseRegister;
        
        BaseTypes_exit();
    }

    delete Cse_LastErrName;
    Cse_LastErrName = NULL;
    delete Cse_LastErrDesc;
    Cse_LastErrDesc = NULL;

    Cse_CleanRecycle();
    delete CseRecycleLock;
    CseRecycleLock = NULL;

    delete CseCharBuffLock;
    CseCharBuffLock = NULL;
    delete CseIntBuffLock;
    CseIntBuffLock = NULL;
    delete CseObjBuffLock;
    CseObjBuffLock = NULL;
    delete CseEntryBuffLock;
    CseEntryBuffLock = NULL;
}

extern "C" {
  CseObj Cse_CreateModule(const TXchar *sModule)
  {
    CseObj mod = Cse_GetModule(sModule,false);
    if (mod == NULL)
    {
        TStolenObj ret(Cse_NewModule(sModule));
        Cse_SetModule(ExtractFileName(sModule),ret);
        return (CseObj) ret;
    }
    else return mod;
  }

  void Cse_SetSymList(CseObj module, const TXchar *name, TInt iFlag)
  {
    Cse_AddSymList(module,name,iFlag,true);
  }

  int Cse_AddSymbol(CseObj module, void *addr)
  {
    return Cse_AddSymAddr(module,addr);
  }

  int Cse_AddOnExit(CseObj module, void *func)
  {
    return Cse_AddExitFunc(module,func);
  }

  void Cse_SetArgument(int argc, TXchar **argv)
  {
    CseModules_SetArg(argc,argv);
  }
}

#if defined(__GNUC__) && !defined(__MINGW32__)
  static void __attribute__((constructor)) CseModules_initEx()
  {
    CseModules_init();
  }

  static void __attribute__((destructor)) CseModules_exitEx()
  {
    CseModules_exit();
  }

#else
  extern "C" BOOL WINAPI DllMain(HANDLE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
  {
    switch(fdwReason)
    {
    case DLL_PROCESS_ATTACH:
        CseModules_init();
        break;

    case DLL_PROCESS_DETACH:
        CseModules_exit();
        break;

    case DLL_THREAD_ATTACH:
        break;

    case DLL_THREAD_DETACH:
        break;
    }

    return TRUE;
  }
#endif
